package com.zhuoyue.biz.core.api.service.impl;

import java.time.LocalDateTime;
import java.util.*;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhuoyue.biz.core.api.dao.DeviceDao;
import com.zhuoyue.biz.core.api.dao.GatewayDao;
import com.zhuoyue.biz.core.api.dao.InfraredDeviceDao;
import com.zhuoyue.biz.core.api.dao.TblDeviceActionsMapper;
import com.zhuoyue.biz.core.api.domain.*;
import com.zhuoyue.biz.core.api.dto.rep.ZigbeeDeviceRepDTO;
import com.zhuoyue.biz.core.api.dto.req.ZigbeeDeviceDTO;
import com.zhuoyue.biz.core.api.service.DeviceActionService;
import com.zhuoyue.biz.core.api.service.ZigbeeDevicePropertyService;
import com.zhuoyue.common.constant.DeviceConstant;
import com.zhuoyue.common.constant.DeviceTypeConstant;
import com.zhuoyue.common.exception.ErrorType;
import com.zhuoyue.common.exception.ZyServerException;
import com.zhuoyue.common.utils.Time;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;


import org.springframework.transaction.annotation.Transactional;


/**
 * @author wjming
 */
@Service
public class DeviceService extends ServiceImpl<DeviceDao, DeviceDO> {

    @Autowired
    private DeviceDao deviceDao;
    @Autowired
    private InfraredDeviceDao infraredDeviceDao;
    @Autowired
    private TblDeviceActionsMapper deviceActionsMapper;
    @Autowired
    private ZigbeeDevicePropertyService zigbeeDevicePropertyService;
    @Autowired
    private GatewayDao gatewayDao;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private DeviceActionService actionService;
    @Autowired
    private ProductInfoAppService productInfoAppService;


    @Transactional(rollbackFor = Exception.class)
    public void multipleDevice(DeviceDO device, Integer multiple) {
        for (int i = 1; i <= multiple; i++) {
            DeviceDO newDevice = new DeviceDO();
            BeanUtils.copyProperties(device, newDevice);
            newDevice.setId(null);
            newDevice.setProductType(device.getProductType() + "_" + i);
            newDevice.setName(device.getName() + "_" + i);

            List<DeviceDO> deviceList = getDeviceList(newDevice);
            if (CollectionUtils.isEmpty(deviceList)) {
                int add = deviceDao.insert(newDevice);
                if (add < 1) {
                    throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
                }
            } else {
                newDevice.setId(deviceList.get(0).getId());
                int update = deviceDao.updateById(newDevice);
                if (update < 1) {
                    throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
                }
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void addSmartAirConditionPanel(String gatewayMac, DeviceDO deviceDO) {
        String zigbeeMac = deviceDO.getZigbeeMac();
        List<TblDeviceActions> deviceActionsList = new ArrayList<>(8);
        //从redis中获取智能空调面板的数据
        String key = gatewayMac + "_" + zigbeeMac;
        Object object = redisTemplate.opsForValue().get(key);
        redisTemplate.delete(key);

        //根据获取的数据，将其添加到数据库
        if (object != null) {
            List<String> deviceList = JSONObject.parseObject(object.toString(), List.class);
            if (deviceList.size() > 0) {
                for (String deviceInfoStr : deviceList) {
                    Map deviceInfo = JSONObject.parseObject(deviceInfoStr);
                    String deviceName = "";
                    String odIndex = deviceInfo.get("odIndex").toString();
                    String deviceType = deviceInfo.get("deviceType").toString();
                    String productType = deviceInfo.get("productType").toString();
                    Map<String, Object> actionsMap = JSONObject.parseObject(deviceInfo.get("actions").toString(), Map.class);
                    switch (StringUtils.substring(productType, productType.indexOf("_"))) {
                        case "_1":
                            deviceName = "空调面板";
                            break;
                        case "_2":
                            deviceName = "地暖面板";
                            break;
                        case "_3":
                            deviceName = "新风面板";
                            break;
                        default:
                            break;
                    }

                    //将设备和actions保存到数据库
                    DeviceDO newDevice = new DeviceDO();
                    org.springframework.beans.BeanUtils.copyProperties(deviceDO, newDevice);
                    newDevice.setId(null);
                    newDevice.setName(deviceName);
                    newDevice.setProductType(productType);
                    // 先查询数据库
                    List<DeviceDO> device = deviceDao.selectList(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getZigbeeMac, zigbeeMac)
                            .eq(DeviceDO::getOdIndex, odIndex).eq(DeviceDO::getDeviceType, deviceType)
                            .eq(DeviceDO::getProductType, productType));
                    // 若数据库中没有设备，则添加；否则通过id修改
                    if (CollectionUtils.isEmpty(device)) {
                        int insertCount = deviceDao.insert(newDevice);
                        if (insertCount < 1) {
                            throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
                        }
                    } else {
                        newDevice.setId(device.get(0).getId());
                        int updateCount = deviceDao.updateById(newDevice);
                        if (updateCount < 1) {
                            throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
                        }
                    }

                    // 添加actions，先删除后添加
                    actionService.remove(Wrappers.<TblDeviceActions>lambdaQuery().eq(TblDeviceActions::getDeviceId, newDevice.getId()));
                    // 取出redis中的actions
                    for (Map.Entry<String, Object> entry : actionsMap.entrySet()) {
                        TblDeviceActions actionsInsert = new TblDeviceActions();
                        actionsInsert.setDeviceId(newDevice.getId());
                        actionsInsert.setActionsKey(entry.getKey());
                        actionsInsert.setActionsValue(entry.getValue().toString());
                        deviceActionsList.add(actionsInsert);
                    }
                }
                // 添加actions
                if (CollectionUtils.isNotEmpty(deviceActionsList)) {
                    actionService.saveBatch(deviceActionsList);
                }
            }
        } else {
            throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
        }
    }


    /**
     * 1:获取设备的信息，看设备是否存在，如果存在看网关是否是同一个，同一个网关就只是执行修改,如果不同网关，先删除在添加
     *
     * @param deviceDTO
     * @return
     */

    @Transactional(rollbackFor = Exception.class)
    public List<DeviceDO> addDevice(ZigbeeDeviceDTO deviceDTO) {
        //判断网关，如果一样，往下直接操作，如果不一样，就需要先把之前的先删除掉再添加
        DeviceDO device = new DeviceDO();
        BeanUtils.copyProperties(deviceDTO, device);
        List<DeviceDO> deviceDo1 = deviceDao.selectList(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getZigbeeMac, device.getZigbeeMac()));

        if (CollectionUtils.isNotEmpty(deviceDo1) && !StringUtils.equals(deviceDo1.get(0).getGatewayId(), device.getGatewayId())) {
            deviceDao.delete(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getZigbeeMac, device.getZigbeeMac()));
        }

        switch (deviceDTO.getDeviceTypeAll()) {
            case DeviceConstant.ProductType.ER_LU_MIAN_BAN:
            case DeviceConstant.ProductType.ER_LU_LIAN_KONG_MIAN_BAN:
                multipleDevice(device, 2);
                break;
            case DeviceConstant.ProductType.SAN_LU_MIAN_BAN:
            case DeviceConstant.ProductType.SAN_LU_LIAN_KONG_MIAN_BAN:
                multipleDevice(device, 3);
                break;
            case DeviceConstant.ProductType.BA_LU_KONG_ZHI_QI:
                multipleDevice(device, 8);
                break;
            case DeviceConstant.ProductType.SI_LU_MIAN_BAN:
            case DeviceConstant.ProductType.SI_LU_LIAN_KONG_MIAN_BAN:
                multipleDevice(device, 4);
                break;
            case DeviceConstant.ProductType.DUO_GONG_NENG_KAI_GUAN:
                add0Faa8A09(device);
                break;

            case DeviceConstant.ProductType.ZHUO_YUE_MIAN_BAN:
                add0Faa8A0A(device, deviceDTO);
                break;
            //智能空调面板
            case DeviceTypeConstant.SMART_AIR_CONDITION_PANEL:
                GatewayDO gatewayDO = gatewayDao.selectById(deviceDTO.getGatewayId());
                if (gatewayDO != null) {
                    addSmartAirConditionPanel(gatewayDO.getZigbeeMac(), device);
                }
                break;
            default:
                DeviceDO deviceDO = getDeviceDo(device);
                if (deviceDO != null) {
                    device.setId(deviceDO.getId());
                    deviceDao.updateById(device);
                } else {
                    int i = deviceDao.insert(device);
                    if (i < 1) {
                        throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
                    }
                }
        }

        List<DeviceDO> deviceList = deviceDao.selectListByQuery(Wrappers.<DeviceDO>lambdaQuery()
                .eq(DeviceDO::getZigbeeMac, device.getZigbeeMac()));

        for (DeviceDO deviceDO : deviceList) {
            if (StringUtils.isEmpty(deviceDO.getActions())) {
                deviceDO.setActions(getActionJson(deviceDO.getId()));
            }
        }
        return deviceList;
    }


    public DeviceDO getDeviceById(String id) {
        return deviceDao.selectAllDeviceById(id);
    }


    public void deleteDeviceById(String deviceId) {
        DeviceDO device = deviceDao.selectById(deviceId);
        if (device == null) {
            throw new ZyServerException(ErrorType.result_not_exist.getCode(), "设备不存在！");
        }
        int count = deviceDao.delete(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getZigbeeMac, device.getZigbeeMac()));
        if (count < 1) {
            throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "Zigbee设备删除失败！");
        }
        //删除对应的红外设备
        infraredDeviceDao.delete(Wrappers.<InfraredDeviceDO>lambdaQuery()
                .eq(InfraredDeviceDO::getDeviceId, deviceId));
    }


    public List<ZigbeeDeviceRepDTO> getDeviceByGatewayId(String gatewayId) {
        List<DeviceDO> list = deviceDao.selectListByQuery(Wrappers.<DeviceDO>lambdaQuery().eq(DeviceDO::getGatewayId, gatewayId));
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }

        //判断是type是否为2，如果为2是wifi设备就去掉
        List<DeviceDO> zigbeeDeviceList = new ArrayList<>();
        for (DeviceDO deviceDO : list
        ) {
            zigbeeDeviceList.add(deviceDO);
        }
        List<ZigbeeDeviceRepDTO> zigbeeDeviceRepDTOList = new ArrayList<>(5);
        // 获取设备状态
        for (DeviceDO deviceDO : list) {

            List<Map<String, String>> listActions = deviceDao.selectDeviceActionsByDeviceId(deviceDO.getId());
            JSONObject actionObj = new JSONObject();
            for (Map<String, String> actionMap : listActions) {
                actionObj.put(actionMap.get("actions_key"), actionMap.get("actions_value"));
            }
            List<String> deviceFun = productInfoAppService.getDeviceFun(deviceDO.getProdId());
            ZigbeeDeviceRepDTO zigbeeDeviceRepDTO = new ZigbeeDeviceRepDTO().deviceDoToDto(deviceDO, null, actionObj.toString(), deviceFun);
            zigbeeDeviceRepDTOList.add(zigbeeDeviceRepDTO);
        }
        return zigbeeDeviceRepDTOList;
    }


    public DeviceDO myUpdateById(DeviceDO device) {
        int byId = deviceDao.updateById(device);
        if (byId < 0) {
            throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "修改设备信息失败");
        }
        DeviceDO deviceDO = deviceDao.selectDeviceById(device.getId());
        return deviceDO;
    }


    /**
     * 添加卓悦面板
     */
    private void add0Faa8A0A(DeviceDO device, ZigbeeDeviceDTO deviceDTO) {
        List<DeviceDO> deviceList = getDeviceList(device);
        int sceneCount = deviceDTO.getSceneCount();
        int switchCount = deviceDTO.getSwitchCount();

        String deviceName = device.getName();
        if (CollectionUtils.isEmpty(deviceList)) {

            //添加场景
            if (sceneCount > 0) {
                DeviceDO deviceDO = new DeviceDO();
                BeanUtils.copyProperties(device, deviceDO);
                deviceDO.setId(null);
                deviceDO.setName(deviceName + "(场景)");
                int add = deviceDao.insert(deviceDO);
                if (add < 1) {
                    throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "场景添加失败");
                }

                Map<String, Object> property = new HashMap<>(2);
                property.put("sceneCount", sceneCount);
                property.put("switchCount", switchCount);

                ZigbeeDeviceProperty zigbeeDeviceProperty = new ZigbeeDeviceProperty();
                zigbeeDeviceProperty.setId(deviceDO.getId());
                zigbeeDeviceProperty.setProperty(JSONObject.toJSONString(property));

                boolean saveFlag = zigbeeDevicePropertyService.save(zigbeeDeviceProperty);
                if (!saveFlag) {
                    throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "添加属性失败");
                }
            }

        } else {
            //修改场景
            device.setId(deviceList.get(0).getId());
            if (sceneCount > 0) {
                device.setName(deviceName);
                int update = deviceDao.updateById(device);
                if (update < 1) {
                    throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备修改失败");
                }
            }
        }
        multipleDevice(device, deviceDTO.getSwitchCount() == null ? 0 : deviceDTO.getSwitchCount());
    }

    /**
     * 多功能开关
     *
     * @param device
     */
    private void add0Faa8A09(DeviceDO device) {
        List<DeviceDO> deviceList = getDeviceList(device);
        if (CollectionUtils.isEmpty(deviceList)) {
            String deviceName = device.getName();
            device.setName(deviceName + "(场景)");
            int add = deviceDao.insert(device);
            if (add < 1) {
                throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
            }
            device.setName(deviceName);
        } else {
            device.setId(deviceList.get(0).getId());
            int update = deviceDao.updateById(device);
            if (update < 1) {
                throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND.getCode(), "设备添加失败");
            }
        }
        multipleDevice(device, 4);
    }

    /**
     * 获取设备列表信息
     *
     * @param device
     * @return
     */
    private List<DeviceDO> getDeviceList(DeviceDO device) {
        return deviceDao.selectList(queryParam(device));
    }

    /**
     * 获取单个设备信息
     *
     * @param device
     * @return
     */
    private DeviceDO getDeviceDo(DeviceDO device) {
        return deviceDao.selectOne(queryParam(device));
    }

    private QueryWrapper<DeviceDO> queryParam(DeviceDO device) {
        QueryWrapper<DeviceDO> queryD = new QueryWrapper();
        queryD.eq("zigbee_mac", device.getZigbeeMac());
        queryD.eq("od_index", device.getOdIndex());
        queryD.eq("device_type", device.getDeviceType());
        queryD.eq("product_type", device.getProductType());
        return queryD;
    }

    /**
     * 获取设备Action信息
     *
     * @param id
     * @return
     */
    public String getActionJson(String id) {
        List<TblDeviceActions> deviceActions = deviceActionsMapper.selectList(Wrappers.<TblDeviceActions>lambdaQuery()
                .eq(TblDeviceActions::getDeviceId, id));
        Map<String, Object> action = new HashMap<>(5);
        for (TblDeviceActions deviceAction : deviceActions) {
            action.put(deviceAction.getActionsKey(), deviceAction.getActionsValue());
        }
        return JSONObject.toJSONString(action);
    }


}
